/****************************************************************************************
**  File: Enabling.hpp
**  Author: Asteroth
**  Date: 3-mag-2009
****************************************************************************************/

#ifndef __ENABLING_HPP__
#define __ENABLING_HPP__

class Enable {
public:
	// Enable alpha test.
	// function: GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL, GL_GREATER, GL_NOTEQUAL, GL_GEQUAL, and GL_ALWAYS
	// reference: the value to compare with
	static inline void alphaTest(GLenum function = GL_GREATER, GLclampf reference = 0) {
		glEnable(GL_ALPHA_TEST);
		glAlphaFunc(function, reference);
	}

	static inline void autoNormal() {glEnable(GL_AUTO_NORMAL);}

	// Enable alpha blending.
	// sourceFactor: GL_ZERO, GL_ONE, GL_DST_COLOR, GL_ONE_MINUS_DST_COLOR, GL_SRC_ALPHA,
	//      GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA, and GL_SRC_ALPHA_SATURATE
	// destFactor: GL_ZERO, GL_ONE, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_SRC_ALPHA,
	//      GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA, and GL_ONE_MINUS_DST_ALPHA
	static inline void blend(GLenum sourceFactor = GL_SRC_ALPHA, GLenum destFactor = GL_ONE_MINUS_SRC_ALPHA) {
		glEnable(GL_BLEND);
		glBlendFunc(sourceFactor, destFactor);
	}

	// Enable clipping planes.
	// clipPlane: GL_CLIP_PLANEi(6)
	// equation: GLdouble[4] - equation of the plane
	static inline void clipPlane(GLenum clipPlane, const GLdouble *equation) {
		glEnable(clipPlane);
		glClipPlane(clipPlane, equation);
	}

	// Enable color operation (default GL_SET).
	// operation: GL_CLEAR, GL_SET, GL_COPY, GL_COPY_INVERTED, GL_NOOP, GL_INVERT, GL_AND,
	//      GL_NAND, GL_OR, GL_NOR, GL_XOR, GL_EQUIV, GL_AND_REVERSE, GL_AND_INVERTED,
	//      GL_OR_REVERSE, and GL_OR_INVERTED
	static inline void colorLogicOperation(GLenum operation) {
		glEnable(GL_COLOR_LOGIC_OP);
		glLogicOp(operation);
	}

	// Enable color material (makes the glColor*() function to set material properties).
	// face: GL_FRONT, GL_BACK, and GL_FRONT_AND_BACK
	// mode: GL_EMISSION, GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR, and GL_AMBIENT_AND_DIFFUSE
	static inline void colorMaterial(GLenum face, GLenum mode) {
		glColorMaterial(face, mode);
		glEnable(GL_COLOR_MATERIAL);
	}

	// Enable cull face.
	// face: GL_FRONT, GL_BACK or GL_FRONT_AND_BACK
	static inline void cullFace(GLenum face = GL_BACK) {
		glEnable(GL_CULL_FACE);
		glCullFace(face);
	}

	// Enable depth test.
	// function: GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL, GL_GREATER, GL_NOTEQUAL, GL_GEQUAL, and GL_ALWAYS
	// near, far: 0..1
	static inline void depthTest(GLenum function = GL_LEQUAL, GLclampd nearDist = 0, GLclampd farDist = 1) {
		glEnable(GL_DEPTH_TEST);
		glDepthFunc(function);
		glDepthRange(nearDist, farDist);
	}

	// Enable dithering.
	static inline void dither() {glEnable(GL_DITHER);}

	// Enable fog.
	// mode: GL_LINEAR, GL_EXP, and GL_EXP2
	static inline void fog(GLenum mode = GL_EXP, GLfloat density = 0.35f, GLfloat start = 1, GLfloat end = 5) {
		glFogi(GL_FOG_MODE, mode);
		glFogf(GL_FOG_DENSITY, density);
		glFogf(GL_FOG_START, start);
		glFogf(GL_FOG_END, end);
		glEnable(GL_FOG);
	}

	// Enable index logic operation (a pre historic functionality?).
	// operation: GL_CLEAR, GL_SET, GL_COPY, GL_COPY_INVERTED, GL_NOOP, GL_INVERT, GL_AND,
	//      GL_NAND, GL_OR, GL_NOR, GL_XOR, GL_EQUIV, GL_AND_REVERSE, GL_AND_INVERTED,
	//      GL_OR_REVERSE, and GL_OR_INVERTED
	static inline void indexLogicOperation(GLenum operation) {
		glEnable(GL_INDEX_LOGIC_OP);
		glLogicOp(operation);
	}

	// Enable line stipple (example pattern: 1110111010011001, resulting drawed line pattern: --- --- -  --  -).
	static inline void lineStipple(GLint factor, GLushort pattern) {
		glEnable(GL_LINE_STIPPLE);
		glLineStipple(factor, pattern);
	}

	// Enable automatic normalization of normals set with glNormal*().
	static inline void normalize() {glEnable(GL_NORMALIZE);}

	// Enable antialiasing with points, lines and polygons.
	static inline void pointSmooth() {glEnable(GL_POINT_SMOOTH);}
	static inline void lineSmooth() {glEnable(GL_LINE_SMOOTH);}
	static inline void polygonSmooth() {glEnable(GL_POLYGON_SMOOTH);}

	// Enable scissor test.
	static inline void scissorTest(GLint x, GLint y, GLsizei width, GLsizei height) {
		glEnable(GL_SCISSOR_TEST);
		glScissor(x, y, width, height);
	}

	// Enable stencil test.
	static inline void stencilTest(GLenum function = GL_ALWAYS, GLint reference = 0, GLuint mask = 1,
		GLenum failOp = GL_KEEP, GLenum zfailOp = GL_KEEP, GLenum zpassOp = GL_KEEP) {
		glEnable(GL_STENCIL_TEST);
		glStencilFunc(function, reference, mask);
		glStencilOp(failOp, zfailOp, zpassOp);
	}

	// Enable texturing.
	static inline void texture1D() {glEnable(GL_TEXTURE_1D);}
	static inline void texture2D() {glEnable(GL_TEXTURE_2D);}
	static inline void texture3D() {glEnable(GL_TEXTURE_3D_EXT);}

	// Enable simulated wiregrame.
	static inline void wireframe() {glPolygonMode(GL_FRONT, GL_LINE);}
};

class Disable {
public:
	static inline void alphaTest()                      { glDisable(GL_ALPHA_TEST); }
	static inline void autoNormal()                     { glDisable(GL_AUTO_NORMAL); }
	static inline void blend()                          { glDisable(GL_BLEND); }
	static inline void clipPlane(GLenum clipPlane)      { glDisable(clipPlane); }
	static inline void colorLogicOperation()            { glDisable(GL_COLOR_LOGIC_OP); }
	static inline void colorMaterial()                  { glDisable(GL_COLOR_MATERIAL); }
	static inline void cullFace()                       { glDisable(GL_CULL_FACE); }
	static inline void depthTest()                      { glDisable(GL_DEPTH_TEST); }
	static inline void dither()                         { glDisable(GL_DITHER); }
	static inline void fog()                            { glDisable(GL_FOG); }
	static inline void indexLogicOperation()            { glDisable(GL_INDEX_LOGIC_OP); }
	static inline void lineStipple()                    { glDisable(GL_LINE_STIPPLE); }
	static inline void normalize()                      { glDisable(GL_NORMALIZE); }
	static inline void pointSmooth()                    { glDisable(GL_POINT_SMOOTH); }
	static inline void lineSmooth()                     { glDisable(GL_LINE_SMOOTH); }
	static inline void polygonSmooth()                  { glDisable(GL_POLYGON_SMOOTH); }
	static inline void scissorTest()                    { glDisable(GL_SCISSOR_TEST); }
	static inline void stencilTest()                    { glDisable(GL_STENCIL_TEST); }
	static inline void texture1D()                      { glDisable(GL_TEXTURE_1D); }
	static inline void texture2D()                      { glDisable(GL_TEXTURE_2D); }
	static inline void texture3D()                      { glDisable(GL_TEXTURE_3D_EXT); }
	static inline void wireframe()                      { glPolygonMode(GL_FRONT, GL_FILL); }
};

#endif
